﻿#include "OpenGLEffectsView.h"
#include "shader/EffectsShaderFactory.h"

#include <QDebug>
#include <QTime>

OpenGLEffectsView::OpenGLEffectsView(QWidget* parent)
	: QOpenGLWidget(parent)
{
	baseShader = EffectsShaderFactory::Get()->GetShader(effectsType);
}

OpenGLEffectsView::~OpenGLEffectsView()
{
	ReleaseEffects();
}

void OpenGLEffectsView::SetEffectsType(OpenGLEffects effectsType)
{
	this->effectsType = effectsType;
	baseShader = EffectsShaderFactory::Get()->GetShader(effectsType);
}

void OpenGLEffectsView::Repaint(AVFrame* frame)
{

	is_draw_end = false;
	//qDebug() << "Repaint->Init";
	if (!frame || frame->width <= 0 || frame->height <= 0)
	{
		qDebug() << "Repaint->error";
		return;
	}
	//std::unique_lock<std::mutex> lock(mux);
	//qDebug() << "Repaint->locked";
	//容错，保证尺寸正确
	if (!datas[0] || width * height == 0 || frame->width != this->width || frame->height != this->height)
	{
		qDebug() << "空数据开始释放内存AVFrame";
		av_frame_free(&frame);
		//lock.unlock();
		return;
	}
	if (width == frame->linesize[0]) //无需对齐
	{
		//qDebug() << "Repaint->无需对齐数据->start";
		memcpy(datas[0], frame->data[0], width * height);
		memcpy(datas[1], frame->data[1], width * height / 4);
		memcpy(datas[2], frame->data[2], width * height / 4);
		//qDebug() << "Repaint->无需对齐数据->end";
	}
	else//行对齐问题
	{
		//qDebug() << "Repaint->逐行copy数据->start";
		for (int i = 0; i < height; i++) //Y 
			memcpy(datas[0] + width * i, frame->data[0] + frame->linesize[0] * i, width);
		for (int i = 0; i < height / 2; i++) //U
			memcpy(datas[1] + width / 2 * i, frame->data[1] + frame->linesize[1] * i, width);
		for (int i = 0; i < height / 2; i++) //V
			memcpy(datas[2] + width / 2 * i, frame->data[2] + frame->linesize[2] * i, width);
		//qDebug() << "Repaint->逐行copy数据->end";

	}

	//qDebug() << "Repaint->释放AVFrame内存";
	if (!frame)
	{
		qDebug() << "Repaint->avframe不可用";
	}
	av_frame_free(&frame);
	//刷新显示
	//qDebug() << "Repaint->update() start!";
	update();
	//qDebug() << "Repaint->update() end!";

}
void OpenGLEffectsView::Init(int width, int height)
{
	//std::unique_lock<std::mutex> lock(mux);
	this->width = width;
	this->height = height;
	delete datas[0];
	delete datas[1];
	delete datas[2];
	///分配材质内存空间
	datas[0] = new unsigned char[width * height];		//Y
	datas[1] = new unsigned char[width * height / 4];	//U
	datas[2] = new unsigned char[width * height / 4];	//V


	if (texs[0])
	{
		glDeleteTextures(3, texs);
	}
	//创建材质
	glGenTextures(3, texs);

	//Y
	glBindTexture(GL_TEXTURE_2D, texs[0]);
	//放大过滤，线性插值   GL_NEAREST(效率高，但马赛克严重)
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	//创建材质显卡空间
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, 0);

	//U
	glBindTexture(GL_TEXTURE_2D, texs[1]);
	//放大过滤，线性插值
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	//创建材质显卡空间
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width / 2, height / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);

	//V
	glBindTexture(GL_TEXTURE_2D, texs[2]);
	//放大过滤，线性插值
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	//创建材质显卡空间
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width / 2, height / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);
}


//初始化opengl
void OpenGLEffectsView::initializeGL()
{
	//std::unique_lock<std::mutex> lock(mux);
	qDebug() << "initializeGL";
	//初始化opengl （QOpenGLFunctions继承）函数 
	initializeOpenGLFunctions();
}

//绑定特效
void OpenGLEffectsView::BindEffects()
{

	//释放特效
	//ReleaseEffects();
	//创建特效
	baseShader->Create([this](int vertexIn_position, int textureIn_position, GLfloat ver[8], GLfloat tex[8]) {
		//启用顶点
		glVertexAttribPointer(vertexIn_position, 2, GL_FLOAT, 0, 0, ver);
		glEnableVertexAttribArray(vertexIn_position);

		//启用材质
		glVertexAttribPointer(textureIn_position, 2, GL_FLOAT, 0, 0, tex);
		glEnableVertexAttribArray(textureIn_position);
		});

	switch (this->effectsType)
	{
	case OpenGLEffects::BLACK_AND_WHITE://阈值
	{
		baseShader->program.setUniformValue("threshold", threshold_value);
	}
		break;
	case OpenGLEffects::GAMMA:
	{
		baseShader->program.setUniformValue("gamma", gamma_value);
	}
		break;
	case OpenGLEffects::NOSTALGIA:
	{
		baseShader->program.setUniformValue("intensity", 0.8f);     // 怀旧效果强度
		baseShader->program.setUniformValue("grainAmount", 0.15f);  // 颗粒感强度
		baseShader->program.setUniformValue("time", QTime::currentTime().msecsSinceStartOfDay() / 1000.0f);  // 动画时间
	}
		break;
	case OpenGLEffects::BRIGHTNESS_EXPOSURE_CONTRAST_STURATION:
	{
		baseShader->program.setUniformValue("brightness", brightness);     // 亮度
		baseShader->program.setUniformValue("exposure", exposure);  // 曝光
		baseShader->program.setUniformValue("contrast", contrast);     // 对比度
		baseShader->program.setUniformValue("saturation", saturation);  // 饱和度
	}
		break;
	case OpenGLEffects::CTRL_L:
	{
		baseShader->program.setUniformValue("shadow", shadow);     // 黑场
		baseShader->program.setUniformValue("highlight", highlight);  // 白场
		baseShader->program.setUniformValue("midtone", midtone);     // 中间调
	}
		break;
	}

}

//释放特效
void OpenGLEffectsView::ReleaseEffects()
{
	//baseShader->Release();
	if (baseShader)
	{
		delete baseShader;
		baseShader = nullptr;
	}
	delete datas[0];
	delete datas[1];
	delete datas[2];
	if (texs[0])
	{
		glDeleteTextures(3, texs);
	}
	EffectsShaderFactory::Get()->Release();
	qDebug() << "已释放了OpenGLWidget窗口资源";
}

//刷新显示
void OpenGLEffectsView::paintGL()
{

	BindEffects();

	if (!datas[0])
	{
		qDebug() << "paintGL->datas[0] 为空";
		return;
	}
	//qDebug() << "paintGL->start";
	//std::unique_lock<std::mutex> lock(mux);
	//qDebug() << "paintGL->locked";
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, texs[0]); //0层绑定到Y材质
	//修改材质内容(复制内存内容)
	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE, datas[0]);
	//与shader uni遍历关联
	glUniform1i(baseShader->unis[0], 0);

	glActiveTexture(GL_TEXTURE0 + 1);
	glBindTexture(GL_TEXTURE_2D, texs[1]); //1层绑定到U材质
	//修改材质内容(复制内存内容)
	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width / 2, height / 2, GL_RED, GL_UNSIGNED_BYTE, datas[1]);
	//与shader uni遍历关联
	glUniform1i(baseShader->unis[1], 1);


	glActiveTexture(GL_TEXTURE0 + 2);
	glBindTexture(GL_TEXTURE_2D, texs[2]); //2层绑定到V材质
	//修改材质内容(复制内存内容)
	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width / 2, height / 2, GL_RED, GL_UNSIGNED_BYTE, datas[2]);
	//与shader uni遍历关联
	glUniform1i(baseShader->unis[2], 2);

	//qDebug() << "paintGL->Draw";
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
	//qDebug() << "paintGL->DrawEnd";
	is_draw_end = true;
}


// 窗口尺寸变化
void OpenGLEffectsView::resizeGL(int width, int height)
{
	qDebug() << "resizeGL " << width << ":" << height;
}
